home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / dsp / drbubtxt / toolstar.z / toolstar / tools / srec.c < prev    next >
Text File  |  1992-04-28  |  39KB  |  1,580 lines

  1. /*
  2.     NAME
  3.         srec - convert Motorola DSP load file records to
  4.                S-record format
  5.  
  6.     SYNOPSIS
  7.         srec [-blmrsw] [-p <procno>] <input file ... >
  8.  
  9.     DESCRIPTION
  10.         Srec takes as input a Motorola DSP absolute load file and
  11.         produces byte-wide Motorola S-record files suitable for
  12.         PROM burning.  If no file is specified the standard input
  13.         is read.  The Motorola DSP START and END records are
  14.         mapped into S0 and S7/S9 records respectively.  All other
  15.         DSP record types are mapped into S1 or S3-type records
  16.         depending on the source processor.  SYMBOL and COMMENT records
  17.         are currently ignored.
  18.  
  19.         Since Motorola DSPs use different word sizes, the words
  20.         must be split into bytes and stored in an appropriate format.
  21.         The program examines the machine type field in the load
  22.         file start record to determine the appropriate S-record
  23.         format to use.  For example, if the machine ID in the START
  24.         record is DSP56000 or DSP5616, srec generates S1/S9 output
  25.         records; if the machine ID is DSP96000, the program generates
  26.         S3/S7 records.
  27.  
  28.         In the default mode of operation the program writes the
  29.         low, middle, and high bytes of each word
  30.         consecutively to the current S1/S3 record being written.  For
  31.         example, given the DSP56000 DATA record below:
  32.  
  33.                 address field
  34.                 |
  35.             _DATA P 0000
  36.             0008F8 300000 340000 094E3E
  37.             |      |      |      |
  38.             |      |      |      fourth word
  39.             |      |      third word
  40.             |      second word
  41.             first word
  42.  
  43.         srec would create the following S1 record:
  44.  
  45.               byte count field
  46.               | address  field              checksum field
  47.               | |                           |
  48.             S10D0000F808000000300000343E4E09F9
  49.                     |     |     |     |
  50.                     |     |     |     fourth word
  51.                     |     |     third word
  52.                     |     second word
  53.                     first word
  54.  
  55.         Output records are written to a file named according to
  56.         the following convention:
  57.  
  58.             <basename>.M
  59.  
  60.         where <basename> is the filename of the input load file
  61.         without extension and M is the memory space specifier
  62.         (X, Y, L, or P) for this set of data words.  Note that a
  63.         separate file is created for each memory space encountered
  64.         in the input stream; thus the maximum number of output files
  65.         in the default mode is 4.
  66.  
  67.         When the -m option is specified, srec splits each DSP source
  68.         word into bytes and stores the bytes in parallel S1/S3
  69.         records.  For example, the following DSP56000 DATA record:
  70.  
  71.                 address field
  72.                 |
  73.             _DATA P 0000
  74.             0008F8 300000 340000 094E3E
  75.             |      |      |      |
  76.             |      |      |      fourth word
  77.             |      |      third word
  78.             |      second word
  79.             first word
  80.  
  81.         would be converted by srec into the three S1 records below:
  82.  
  83.               byte count field
  84.               | address  field
  85.               | |
  86.             S1070000F800003EC2 -- low  byte
  87.             S10700000800004EA2 -- mid  byte
  88.             S1070000003034098B -- high byte
  89.                 | | | | |
  90.                 | | | | checksum field
  91.                 | | | fourth word
  92.                 | | third word
  93.                 | second word
  94.                 first word
  95.  
  96.         The three records corresponding to the high, middle, and
  97.         low bytes of each data word are written to separate files.
  98.         The files are named according to the following convention:
  99.  
  100.             <basename>.<M><#>
  101.  
  102.         where <basename> is the filename of the input load file
  103.         without extension, <M> is the memory space specifier
  104.         (X, Y, L, or P) for this set of data words, and # is
  105.         one of the digits 0, 1, or 2 corresponding to low, middle,
  106.         and high bytes, respectively.  If input comes from the
  107.         standard input, the module name is used as <basename>.
  108.  
  109.         Note that a separate set of byte-wide files is created for
  110.         each memory space encountered in the input stream.  Thus the
  111.         number of output files generated is (number of memory spaces
  112.         in input * size of DSP word).
  113.  
  114.         The -s option writes all information to a single file,
  115.         storing the memory space information in the address field
  116.         of the S0 header record.  The values stored in the address
  117.         field and their correspondence to the DSP56000 memory
  118.         spaces are as follows:
  119.  
  120.             Value        DSP56000 Memory Space
  121.             -----        ---------------------
  122.               1            X
  123.               2            Y
  124.               3            L
  125.               4            P
  126.  
  127.         When the memory space changes in the DATA or BLOCKDATA
  128.         record, a new S0 header record is generated.  The resulting
  129.         output file is named <basename>.s, where <basename> is
  130.         the filename of the input load file without extension.
  131.         The -m and -s options are mutually exclusive.
  132.  
  133.         The -r option causes srec to write bytes high to low rather
  134.         than low to high in the default and -s modes.  It has no
  135.         affect when the -m option is given.
  136.  
  137.         Address fields in DSP load records are copied as is to
  138.         the appropriate S1 or S3 record.  Subsequent S1 or S3
  139.         record addresses are byte incremented until a new DATA
  140.         record is encountered or end-of-file is reached.  In some
  141.         cases the starting S1/S3 record address must be adjusted for
  142.         byte addressing by multiplying the load record start address
  143.         by the number of bytes in a DSP56000 word.  When the -b
  144.         option is given, any DATA record address fields are adjusted
  145.         to begin on a byte-multiple address.  If the -w option is
  146.         specified (the default) byte-incrementing is not done
  147.         when generating S-record addresses, e.g. the S-record
  148.         addresses are word-oriented rather than byte-oriented.
  149.         The -b and -w options have no effect when used in conjunction
  150.         with the -m mode, since in that case byte and word address
  151.         mappings are 1:1.
  152.  
  153.         DATA records for L space memory contain words which are loaded
  154.         into adjacent X and Y memory locations.  In these cases
  155.         performing the default strict word addressing may be
  156.         inappropriate.  The -l option can be given to indicate
  157.         that double-word addressing should be used to generate
  158.         subsequent S1/S3 addresses after the initial load address.
  159.         In addition the -l option should be used when doing byte
  160.         addressing since the initial load addresses must be adjusted
  161.         to account for double-word addressing in the load file.
  162.         In general, it is a good idea to use the -l option whenever
  163.         the source load file contains DATA records which refer to
  164.         L memory space.
  165.  
  166.         In the START record only the module id is passed as header
  167.         data for the S0 record; the version number, revision number,
  168.         and comment are ignored.  As noted earlier, the machine ID
  169.         field is used to determine what type of S-records to generate
  170.         based on the addressing range of the DSP processor.  Some
  171.         load file generators may not produce a START record or the
  172.         START record may not contain the processor type.  The -p
  173.         option can be used to explicitly specify a processor load file
  174.         format.  Note that the -p option overrides the machine ID
  175.         given in the START record.
  176.  
  177.     OPTIONS
  178.         -b    - use byte addressing when transferring load addresses
  179.               to S-record addresses.  This means that load file
  180.               DATA record start addresses are multiplied by
  181.               the DSP bytes/word and subsequent S1/S3 record
  182.               addresses are computed based on the data byte count.
  183.         -l    - use double-word addressing when transferring load
  184.               addresses from L space to S-record addresses.  This
  185.               means that load file DATA records for L space data
  186.               are moved unchanged and subsequent S1/S3 record
  187.               addresses are computed based on the data word count
  188.               divided by 2.  This option should always be used
  189.               when the source load file contains DATA records in L
  190.               memory space.
  191.         -m    - split each DSP word into bytes and store
  192.               the bytes in parallel S-records.   Replaces
  193.               the -3 option.  The -m and -s options are
  194.               mutually exclusive.
  195.         -p    - assume <procno> load file input format.  <procno>
  196.               is one of the Motorola DSP processor numbers, e.g.
  197.               56000, 96000, etc.
  198.         -r    - write bytes high to low, rather than low to
  199.               high.  Has no effect when used with -m option.
  200.         -s    - write data to a single file, putting memory
  201.               space information into the address field of the
  202.               S0 header record. Replaces the -1 option.
  203.               Bytes may be reversed with the -r option.
  204.               The -m and -s options are mutually exclusive.
  205.         -w    - use word addressing when transferring load addresses
  206.               to S-record addresses.  This means that load file
  207.               DATA record start addresses are moved unchanged and
  208.               subsequent S1/S3 record addresses are computed
  209.               based on the data word count.
  210.  
  211.     DIAGNOSTICS
  212.         The program does some checking for invalid input record
  213.         formats, memory spaces, and hex values.  It obviously
  214.         cannot check for bad data values if the load file has
  215.         been tampered with.  Both START and END records should be
  216.         found in the input stream, but the program tries to be
  217.         forgiving about this.  If a START record is not present
  218.         then the -p option should be used.
  219.  
  220.     IMPLEMENTATION NOTES
  221.         One (and only one) of the operating system DEFINEs below
  222.         must be activated to obtain appropriate conditional
  223.         compilation.  This can be done either directly in the source
  224.         by changing the 0 DEFINE for the desired operating system
  225.         to a 1, or via the compiler command line (ex. -DATT=1).
  226.         Note that the UNIX flag is simply a logical ORing of the
  227.         more specific Unix OS flags (ATT and BSD) and thus should
  228.         not be specified explicitly.
  229.  
  230.     HISTORY
  231.         1.0    The beginning.
  232.         1.1    Added code to support new default mode and -r
  233.             option (-3 was old default mode).
  234.         1.2    Added support for AT&T Unix System V.
  235.         1.3    Fix for bug in default mode where S-record address
  236.             was not being computed correctly (e.g. not a byte
  237.             multiple of the 56000 word size).
  238.         1.4    Added support for Macintosh II.
  239.         1.5    Added separate include file, getopt () support,
  240.             -1 (single output file) option.
  241.         1.6    Fix for bug in default mode when handling BLOCKDATA
  242.             records; repeated call to reverse bytes was reversing
  243.             bytes in place!
  244.         1.7    Added -b and -w options.
  245.         2.1    Bumped version number for distribution.
  246.         3.0    Added DSP96000 support; replaced -1 and -3 options
  247.             with -s and -m respectively.
  248.         3.1    Modified get_start() to handle old-style START
  249.             records (e.g. without error count, machine type,
  250.             assembler version, etc.).
  251.         3.2    Added -l option.
  252.         4.0    Added DSP5616 support.
  253.         4.1    Fixed bug in S7/S9 generation code (get_end()) where
  254.             with -b option address was not transferred correctly
  255.             to output field, resulting in a bad S7/S9 checksum.
  256.         4.2    Added standard input capability.
  257.         4.3    Fixed so data field lengths can vary.
  258.         4.4    Changed standard input to use "-" command line flag;
  259.             no options causes usage to be printed.  Filled out
  260.             option descriptions in usage message.
  261.         4.5    Fixed bug in handling of S-record count fields to
  262.             deal with long values on 16-bit hosts (IBM PC).
  263.         4.6    Name change from DSP56016 to DSP5616.
  264.         4.7    Fixed bug in rev_bytes logic for 5616, 96000.
  265.         4.8    Added -p option; made START/END record parsing
  266.             more forgiving.
  267.         4.9    Made record type names case-insensitive.
  268.         4.10    Fixed bugs in old-style START record logic.
  269. */
  270.  
  271.  
  272. #include <stdio.h>
  273. #include <ctype.h>
  274. #include <signal.h>
  275. #include <setjmp.h>
  276. #if VMS
  277. #include <descrip.h>
  278. #include <ssdef.h>
  279. #include <stsdef.h>
  280. #include <climsgdef.h>
  281. #endif
  282. #if MPW
  283. #include <files.h>
  284. #include <CursorCtl.h>
  285. #ifdef String
  286. #undef String
  287. #endif
  288. #endif    /* MPW */
  289. #include "srec.h"
  290.  
  291.  
  292. extern int main ( /* int argc,char *argv [] */ );
  293. static do_srec ( /* FILE *fp */ );
  294. static get_start ( /* FILE *fp */ );
  295. static get_record ( /* void */ );
  296. static get_data ( /* void */ );
  297. static get_bdata ( /* void */ );
  298. static get_end ( /* void */ );
  299. static sum_addr ( /* unsigned long addr */ );
  300. static get_bytes ( /* int space */ );
  301. static flush_rec ( /* int space,unsigned long addr,unsigned long count */ );
  302. static rev_bytes ( /* void */ );
  303. static open_files ( /* int space */ );
  304. static get_field ( /* void */ );
  305. static get_comment ( /* void */ );
  306. static get_line ( /* void */ );
  307. static char *scan_field ( /* char *bp */ );
  308. static bld_s0 ( /* unsigned space */ );
  309. static setup_mach ( /* char *buf */ );
  310. static get_space ( /* void */ );
  311. static char *fix_fname ( /* char *fname */ );
  312. static char *strup ( /* char *str */ );
  313. static fldhex ( /* void */ );
  314. static char *basename ( /* char *str */ );
  315. static setfile ( /* char *fn,char *type,char *creator */ );
  316. extern int getopt ( /* int argc,char *argv [],char *optstring */ );
  317. #if VMS
  318. static dcl_getval ( /* struct dsc$descriptor_s *opt */ );
  319. #else
  320. static dcl_getval ( /* int *opt */ );
  321. #endif
  322. #if BSD
  323. static int onintr ( /* void */ );
  324. #else
  325. static void onintr ( /* void */ );
  326. #endif
  327. static usage ( /* void */ );
  328. static error ( /* char *str */ );
  329. static error2 ( /* char *fmt,char *str */ );
  330.  
  331.  
  332. char *optarg = NULL;            /* command argument pointer */
  333. int optind = 0;                /* command argument index */
  334.  
  335. char Progdef[] = "srec";        /* program default name */
  336. char *Progname = Progdef;        /* pointer to program name */
  337. char Progtitle[] = "Motorola DSP S-Record Conversion Utility";
  338. char Version[]   = "Version 4.10";    /* srec version number */
  339. char Copyright[] = "(C) Copyright Motorola, Inc. 1987, 1988, 1989, 1990.  All rights reserved.";
  340. static dclflag = NO;            /* VMS DCL flag */
  341. static char *ifname = NULL;        /* pointer to input file name */
  342. static FILE *ifile = NULL;        /* file pointer for input file */
  343. static opts = NO;            /* single file option flag */
  344. static optm = NO;            /* multiple file option flag */
  345. static reverse = NO;            /* reverse byte option flag */
  346. static baddr = NO;            /* byte address flag */
  347. static waddr = NO;            /* word address flag */
  348. static lmem = NO;            /* L memory flag */
  349. static unsigned linecount = 1;        /* input file line count */
  350. static char fldbuf[MAXSTR] = {EOS};    /* Object file field buffer */
  351. static char strbuf[MAXSTR] = {EOS};    /* Global string buffer */
  352. static char s0buf[MAXSTR];        /* S0 record string */
  353. static unsigned s0cnt = S0OVRHD;    /* S0 byte count */
  354. static unsigned s0addr = 0;        /* S0 address */
  355. static unsigned s0sum = 0;        /* S0 checksum */
  356. static mach = NONE;            /* source machine type */
  357. static wsize = 0;            /* bytes per DSP word */
  358. static ovrhd = 0;            /* overhead bytes in S-record */
  359. static char *wrdfmt = NULL;        /* word format string */
  360.  
  361. /*
  362.     pointers to S-record structure arrays
  363. */
  364. static struct srec *rec[] = {NULL, NULL, NULL, NULL};
  365.  
  366. extern char *calloc (), *malloc ();
  367. #if BSD
  368. extern char *index (), *rindex ();
  369. #else
  370. extern char *strchr (), *strrchr ();
  371. #endif
  372. char *strup ();
  373. #if LSC
  374. jmp_buf Env;
  375. #endif
  376. extern char *getenv ();
  377.  
  378. static char dclbuf[MAXSTR];
  379. #if VMS                    /* VMS DCL cmd line opt descriptors */
  380. $DESCRIPTOR(arg_desc, dclbuf);
  381. $DESCRIPTOR(lod_desc, "LOAD");
  382. $DESCRIPTOR(byt_desc, "BYTE");
  383. $DESCRIPTOR(lng_desc, "LONG");
  384. $DESCRIPTOR(mlt_desc, "MULT");
  385. $DESCRIPTOR(prc_desc, "PROC");
  386. $DESCRIPTOR(rev_desc, "REVERSE");
  387. $DESCRIPTOR(sgl_desc, "SINGLE");
  388. $DESCRIPTOR(wrd_desc, "WORD");
  389. #else
  390. int lod_desc;
  391. #endif
  392.  
  393.  
  394. #if !LSC
  395. main (argc, argv)
  396. #else
  397. _main (argc, argv)
  398. #endif
  399. int argc;
  400. char *argv[];
  401. {
  402. #if BSD
  403.     int onintr (), onsegv ();
  404. #else
  405.     void onintr (), onsegv ();
  406. #endif
  407.     int c;
  408.     char *p, *q, *fn, *procno = NULL;
  409.     char *basename(), *getenv();
  410.     char *fix_fname ();
  411.  
  412. /*
  413.     set up for signals; get prog. name, check for command line options
  414. */
  415.  
  416. #if AZTEC
  417.     (void)sigset (SIGINT, onintr);    /* set up for signals */
  418. #else
  419.     (void)signal (SIGINT, onintr);    /* set up for signals */
  420. #endif
  421.     p = basename (argv[0]);    /* get command base name */
  422.     if ((q = strrchr (p, '.')) != NULL)
  423.         *q = EOS;
  424. #if VMS
  425.     if ((q = strrchr (p, ';')) != NULL)
  426.         *q = EOS;
  427.     dclflag = getenv (p) == NULL;
  428. #endif
  429. #if MSDOS
  430.     if (_osmajor > 2)
  431. #endif
  432.         Progname = p;
  433.  
  434. #if MSDOS
  435.         (void)fprintf (stderr, "%s  %s\n%s\n", Progtitle, Version, Copyright);
  436. #endif
  437.  
  438.     if (!dclflag) {        /* not using VMS DCL */
  439.  
  440.         optarg = NULL;        /* command argument pointer */
  441.         optind = 0;        /* command argument index */
  442.         while ((c = getopt (argc, argv, "blmp:rsw?")) != EOF) {
  443.             switch (c) {
  444.             case 'b':    baddr = YES;
  445.                     break;
  446.             case 'l':    lmem = YES;
  447.                     break;
  448.             case 'm':    optm = YES;
  449.                     break;
  450.             case 'p':    procno = optarg;
  451.                     break;
  452.             case 'r':    reverse = YES;
  453.                     break;
  454.             case 's':    opts = YES;
  455.                     break;
  456.             case 'w':    waddr = YES;
  457.                     break;
  458.             case '?':
  459.             default:    usage ();
  460.                     break;
  461.             }
  462.         }
  463.         argc -= optind;        /* adjust argument count */
  464.         argv = &argv[optind];    /* reset argv pointer */
  465.         if (argc <= 0 || (opts && optm) || (baddr && waddr))
  466.             usage (); /* no more args or mutually exclusive args */
  467.  
  468.     } else {    /* using VMS DCL */
  469. #if VMS
  470.         if (cli$present (&byt_desc) == CLI$_PRESENT)
  471.             baddr = YES;
  472.         if (cli$present (&lng_desc) == CLI$_PRESENT)
  473.             lmem = YES;
  474.         if (cli$present (&mlt_desc) == CLI$_PRESENT)
  475.             optm = YES;
  476.         if (dcl_getval (&prc_desc) != CLI_ABSENT)
  477.             procno = dclbuf;
  478.         if (cli$present (&rev_desc) == CLI$_PRESENT)
  479.             reverse = YES;
  480.         if (cli$present (&sgl_desc) == CLI$_PRESENT)
  481.             opts = YES;
  482.         if (cli$present (&wrd_desc) == CLI$_PRESENT)
  483.             waddr = YES;
  484. #endif
  485.     }
  486.  
  487. /*
  488.     Set processor type if necessary
  489. */
  490.  
  491.     if (procno && (mach = setup_mach (procno)) == NONE)
  492.         error ("invalid machine type");
  493.  
  494. /*
  495.     Loop to process files
  496. */
  497.  
  498.     while (dclflag ? dcl_getval (&lod_desc) != CLI_ABSENT : argc) {
  499.         fn = dclflag ? dclbuf : *argv;
  500.         if (strcmp (fn, "-") == 0) {
  501.             ifile = stdin;        /* use standard input */
  502.             do_srec (ifile);    /* process records */
  503. #if VAX
  504.         } else if (strcmp (strup (fn), "SYS$INPUT") == 0) {
  505.             ifile = stdin;        /* use standard input */
  506.             do_srec (ifile);    /* process records */
  507. #endif
  508.         } else {
  509.             ifname = fix_fname (fn);/* fix file name */
  510.             if (!(ifile = fopen (ifname, "r")))
  511.                 error2 ("cannot open input file %s", ifname);
  512.             if ((p = strrchr (ifname, '.')) != NULL)
  513.                 *p = EOS;    /* strip extension */
  514.             do_srec (ifile);    /* process records */
  515.             (void)fclose (ifile);    /* close input file */
  516.         }
  517.         free (ifname);    /* free file name */
  518.         if (!dclflag) {
  519.             argv++;    /* bump arg pointer */
  520.             argc--;    /* decrement arg counter (MPW 3.0 kludge) */
  521.         }
  522.     }
  523.  
  524.  
  525.  
  526. #if LSC
  527.     return (OK);
  528. #else
  529.     exit (OK);
  530. #endif
  531. }
  532.  
  533.  
  534. static
  535. do_srec (fp)        /* process load file records */
  536. FILE *fp;
  537. {
  538.     if (!get_start (fp))        /* no START record */
  539.         error ("no START record");
  540.  
  541.     while (!feof (fp)) {        /* loop while not end-of-file */
  542.  
  543.         switch (get_record ()) {
  544.         case START:
  545.             error ("duplicate START record");
  546.         case END:
  547.             get_end ();
  548.             return;
  549.         case DATA:
  550.             get_data ();
  551.             break;
  552.         case BDATA:
  553.             get_bdata ();
  554.             break;
  555.         case COMMENT:
  556.             (void)get_comment ();
  557.             break;
  558.         case SYMBOL:
  559.             fldbuf[0] = EOS; /* skip SYMBOL records */
  560.             break;
  561.         default:
  562.             if (!feof (fp))
  563.                 error ("invalid record type");
  564.         }
  565.     }
  566.     /* should never get here if END record found */
  567.     if (feof (fp))
  568.         get_end ();        /* be forgiving */
  569. }
  570.  
  571.  
  572. static
  573. get_start (fp)        /* process START record */
  574. FILE *fp;
  575. {
  576.     int type, old = NO;
  577.     char *fbp = fldbuf;
  578.     char *sbp = s0buf;
  579.     char *lbp = strbuf;
  580.     char *p, *scan_field ();
  581.  
  582. /*
  583.     locate START record
  584. */
  585.  
  586.     while ((type = get_record ()) <= 0)
  587.         ;    /* look for record identifier */
  588.  
  589.     if (type == EOF)
  590.         return (NO);
  591.  
  592.     if (type != START) {    /* be forgiving */
  593.         if (!mach && (mach = setup_mach ("56000")) == NONE)
  594.             error ("cannot initialize machine type");
  595.         bld_s0 ((unsigned)NONE);
  596.         if (opts)    /* single file option */
  597.             open_files (NONE);
  598.         return (YES);
  599.     }
  600.  
  601.     if (get_line () < 0)        /* buffer entire line */
  602.         error ("invalid START record");
  603.  
  604. /*
  605.     get program name; loop to put into header string
  606. */
  607.  
  608.     if ((lbp = scan_field (lbp)) == NULL)    /* pick up program name */
  609.         error ("invalid START record");    /* got to have a name */
  610.  
  611.     if (fp == stdin) {        /* use module name for output */
  612.         ifname = fix_fname (fldbuf);
  613.         if ((p = strrchr (ifname, '.')) != NULL)
  614.             *p = EOS;        /* strip extension */
  615.     }
  616.  
  617.     while (*fbp) {
  618.         (void)sprintf (sbp, "%02x", *fbp);
  619.         s0sum += (unsigned)(*fbp++ & 0xff);
  620.         sbp += 2;
  621.         s0cnt++;
  622.     }
  623.  
  624. /*
  625.     build S0 record
  626. */
  627.  
  628.     bld_s0 ((unsigned)NONE);
  629.  
  630.     if (((lbp = scan_field (lbp)) == NULL) || /* skip version number */
  631.         ((lbp = scan_field (lbp)) == NULL) || /* skip revision number */
  632.         ((lbp = scan_field (lbp)) == NULL))   /* skip error count */
  633.         old = YES;        /* wierd or old-style START record */
  634.  
  635.     if (old) {        /* look for machine type */
  636.         if (!mach && (mach = setup_mach ("56000")) == NONE)
  637.             error ("cannot initialize machine type");
  638.     } else {
  639.         /* already got error count in last scan_field() call.... */
  640.  
  641.         if ((lbp = scan_field (lbp)) == NULL)    /* machine ID */
  642.             error ("invalid START record");
  643.  
  644.         if (strncmp (fldbuf, "DSP", 3) != 0)
  645.             error ("invalid START record");
  646.  
  647.         if (!mach && (mach = setup_mach (&fldbuf[3])) == NONE)
  648.             error ("invalid machine type");
  649.  
  650.         if ((lbp = scan_field (lbp)) == NULL)    /* skip asm version */
  651.             error ("invalid START record");
  652.     }
  653.  
  654.     if (get_comment () < 0)        /* skip comment */
  655.         error ("invalid START record");
  656.  
  657.     if (opts)            /* single file option */
  658.         open_files (NONE);
  659.  
  660.     return (YES);
  661. }
  662.  
  663.  
  664. static
  665. get_record ()        /* look for next record in load file input */
  666. {
  667.     int field = 0;
  668.     char *fbp = fldbuf + 1;
  669.  
  670. #if MPW
  671.     SpinCursor (4);
  672. #endif
  673.     while (fldbuf[0] != NEWREC && (field = get_field ()) == 0)
  674.         ;
  675.  
  676.     if (field < 0)
  677.         return (field);
  678.  
  679.     (void) strup (fbp);
  680.     if (strcmp (fbp, "DATA") == 0)
  681.         return (DATA);
  682.     if (strcmp (fbp, "BLOCKDATA") == 0)
  683.         return (BDATA);
  684.     if (strcmp(fbp, "START") == 0)
  685.         return (START);
  686.     if (strcmp (fbp, "END") == 0)
  687.         return (END);
  688.     if (strcmp (fbp, "SYMBOL") == 0)
  689.         return (SYMBOL);
  690.     if (strcmp (fbp, "COMMENT") == 0)
  691.         return (COMMENT);
  692.  
  693.     return (NONE);
  694. }
  695.  
  696.  
  697. static
  698. get_data ()        /* process DATA records */
  699. {
  700.     int space, spc, i;
  701.     unsigned long addr, val, count = 0L;
  702.     struct srec *drec;
  703.  
  704.     if (get_field () < 0)        /* pick up memory space */
  705.         error ("invalid DATA record");
  706.  
  707.     if ((spc = space = get_space ()) < 0)
  708.         error ("invalid memory space specifier");
  709.  
  710.     if (opts) {            /* single file option */
  711.         i = space + 1;
  712.         space = NONE;
  713.         if (s0addr != (unsigned)i) {
  714.             bld_s0 ((unsigned)i);
  715.             fputs (s0buf, rec[0]->fp);
  716.             s0addr = (unsigned)i;
  717.         }
  718.     } else
  719.         if (!rec[space])    /* see if files are open */
  720.             open_files (space);
  721.  
  722.     if (get_field () < 0)        /* read in address field */
  723.         error ("invalid DATA record");
  724.     if (!fldhex ())
  725.         error ("invalid address value");
  726.     (void)sscanf (fldbuf, "%lx", &addr);    /* convert address */
  727.     if (!optm && baddr)
  728.         addr *= wsize;        /* adjust address for serial bytes */
  729.     if (lmem && baddr)
  730.         addr *= 2;        /* adjust address for long memory */
  731.  
  732. /*
  733.     initialize data record fields
  734. */
  735.  
  736.     for (i = 0, drec = rec[space]; i < (optm ? wsize : 1); i++, drec++) {
  737.         drec->checksum = 0;
  738.         drec->p = drec->buf;
  739.     }
  740.  
  741. /*
  742.     loop to pick up data
  743. */
  744.  
  745.     while (get_field () == 0) {    /* get next data field */
  746.  
  747.         if (!fldhex ())
  748.             error ("invalid data value");
  749.         (void) sscanf (fldbuf, "%lx", &val);
  750.         (void) sprintf (fldbuf, wrdfmt, val);
  751.         (void) strup (fldbuf);
  752.         if (strlen (fldbuf) != wsize * 2)
  753.             error ("improper number of bytes in word");
  754.         if (!reverse && !optm)
  755.             rev_bytes ();
  756.         get_bytes (space);    /* extract bytes from field */
  757.  
  758. /*
  759.     if max record count reached, print out current record
  760. */
  761.  
  762.         count += optm ? 1L : wsize;
  763.         if (!(count & 1L) && count >= MAXBYTE) {
  764.             flush_rec (space, addr, count);
  765.             if (waddr && !optm) {
  766.                 if (lmem && spc == LMEM)
  767.                     addr += (count / wsize) / 2L;
  768.                 else
  769.                     addr += count / wsize;
  770.             } else
  771.                 addr += count;
  772.             count = 0L;
  773.         }
  774.     }
  775.  
  776. /*
  777.     new record or EOF encountered; flush out current record
  778. */
  779.  
  780.     if (rec[space]->p != rec[space]->buf)
  781.         flush_rec (space, addr, count);
  782. }
  783.  
  784.  
  785. static
  786. get_bdata ()        /* process BLOCKDATA records */
  787. {
  788.     int space, spc, i, j;
  789.     unsigned long addr, val, count = 0L;
  790.     unsigned repeat;
  791.     struct srec *drec;
  792.  
  793.     if (get_field () < 0)        /* pick up memory space */
  794.         error ("invalid BLOCKDATA record");
  795.  
  796.     if ((spc = space = get_space ()) < 0)
  797.         error ("invalid memory space specifier");
  798.  
  799.     if (opts) {            /* single file option */
  800.         i = space + 1;
  801.         space = NONE;
  802.         if (s0addr != (unsigned)i) {
  803.             bld_s0 ((unsigned)i);
  804.             fputs (s0buf, rec[0]->fp);
  805.             s0addr = (unsigned)i;
  806.         }
  807.     } else
  808.         if (!rec[space])    /* see if files are open */
  809.             open_files (space);
  810.  
  811.     if (get_field () < 0)        /* read in address field */
  812.         error ("invalid BLOCKDATA record");
  813.     if (!fldhex ())
  814.         error ("invalid address value");
  815.     (void)sscanf (fldbuf, "%lx", &addr);    /* convert address */
  816.     if (!optm && baddr)
  817.         addr *= wsize;        /* adjust address for serial bytes */
  818.     if (lmem && baddr)
  819.         addr *= 2;        /* adjust address for long memory */
  820.  
  821.     if (get_field () < 0)        /* read in repeat field */
  822.         error ("invalid BLOCKDATA record");
  823.     if (!fldhex ())
  824.         error ("invalid count value");
  825.     (void)sscanf (fldbuf, "%x", &repeat);    /* save repeat value */
  826.  
  827.     if (get_field () < 0)        /* read in value field */
  828.         error ("invalid BLOCKDATA record");
  829.     if (!fldhex ())
  830.         error ("invalid data value");
  831.     (void) sscanf (fldbuf, "%lx", &val);
  832.     (void) sprintf (fldbuf, wrdfmt, val);
  833.     (void) strup (fldbuf);
  834.     if (strlen (fldbuf) != wsize * 2)
  835.         error ("improper number of bytes in word");
  836.     if (!fldhex ())
  837.         error ("invalid data value");
  838.     if (!reverse && !optm)
  839.         rev_bytes ();
  840.  
  841. /*
  842.     initialize data record fields
  843. */
  844.  
  845.     for (i = 0, drec = rec[space]; i < (optm ? wsize : 1); i++, drec++) {
  846.         drec->checksum = 0;
  847.         drec->p = drec->buf;
  848.     }
  849.  
  850. /*
  851.     loop to generate data records
  852. */
  853.  
  854.     for (j = 0; j < repeat; j++) {
  855.  
  856.         get_bytes (space);    /* extract bytes from field */
  857.  
  858. /*
  859.     if max record count reached, print out current record
  860. */
  861.  
  862.         count += optm ? 1L : wsize;
  863.         if (!(count & 1L) && count >= MAXBYTE) {
  864.             flush_rec (space, addr, count);
  865.             if (waddr && !optm) {
  866.                 if (lmem && spc == LMEM)
  867.                     addr += (count / wsize) / 2L;
  868.                 else
  869.                     addr += count / wsize;
  870.             } else
  871.                 addr += count;
  872.             count = 0L;
  873.         }
  874.     }
  875.  
  876. /*
  877.     new record or EOF encountered; flush out current record
  878. */
  879.  
  880.     if (rec[space]->p != rec[space]->buf)
  881.         flush_rec (space, addr, count);
  882. }
  883.  
  884.  
  885. static
  886. get_end ()        /* process END record, clean up, and exit */
  887. {
  888.     int i, field, space;
  889.     unsigned long count = 1;    /* always a checksum byte */
  890.     unsigned long addr, checksum = 0;
  891.     struct srec *drec;
  892.  
  893.     if ((field = get_field ()) > 0)    /* try to get address field */
  894.         error ("invalid END record");
  895.  
  896.     if (field == 0) {
  897.         if (!fldhex ())
  898.             error ("invalid address value");
  899.         (void)sscanf (fldbuf, "%lx", &addr);    /* convert address */
  900.         if (!optm && baddr)
  901.             addr *= wsize;    /* adjust address for serial bytes */
  902.         if (mach == DSP56000 || mach == DSP5616)
  903.             (void)sprintf (fldbuf, "%04lx", addr);
  904.         else
  905.             (void)sprintf (fldbuf, "%08lx", addr);
  906.         checksum = (unsigned)sum_addr (addr);
  907.         count = ovrhd;
  908.     }
  909.  
  910.     for (space = 0; space < (opts ? 1 : MSPACES); space++) {
  911.         if (rec[space]) {
  912.             for (i = 0, drec = opts ? rec[0] : rec[space];
  913.                  i < (optm ? wsize : 1); i++, drec++) {
  914.                 if (mach == DSP56000 || mach == DSP5616)
  915.                     (void)sprintf (strbuf,
  916.                         "S9%02lx%s%02x\n",
  917.                         count,
  918.                         field == 0 ? fldbuf : "",
  919.                         ~(checksum + count) & 0xff);
  920.                 else
  921.                     (void)sprintf (strbuf,
  922.                         "S7%02lx%s%02x\n",
  923.                         count,
  924.                         field == 0 ? fldbuf : "",
  925.                         ~(checksum + count) & 0xff);
  926.                 fputs (strup (strbuf), drec->fp);
  927.                 (void)fclose (drec->fp);
  928.             }
  929.             free ((char *)rec[space]);
  930.             rec[space] = NULL;
  931.         }
  932.     }
  933. }
  934.  
  935.  
  936. static
  937. sum_addr (addr)        /* sum bytes of address */
  938. unsigned long addr;
  939. {
  940.     int i, sum;
  941.  
  942.     for (i = 0, sum = 0; i < sizeof (unsigned long); i++) {
  943.         sum += addr & 0xff;
  944.         addr >>= 8;
  945.     }
  946.     return (sum);
  947. }
  948.  
  949.  
  950. static
  951. get_bytes (space)    /* move bytes from field buffer into record buffer */
  952. int space;
  953. {
  954.     int i, j;
  955.     register char *fbp, *p;
  956.     struct srec *drec;
  957.  
  958.     fbp = fldbuf;
  959.     /* loop to move bytes, sum for checksum */
  960.     for (i = 0, drec = rec[space]; i < wsize; i++, drec += optm ? 1 : 0) {
  961.         p = drec->p;
  962.         *p++ = *fbp++;
  963.         *p++ = *fbp++;
  964.         *p = EOS;
  965.         (void)sscanf (drec->p, "%x", &j);
  966.         drec->checksum += (unsigned)j;
  967.         drec->p = p;
  968.     }
  969. }
  970.  
  971.  
  972. static
  973. flush_rec (space, addr, count)    /* flush S1/S3 record to appropriate file */
  974. int space;
  975. unsigned long addr, count;
  976. {
  977.     int i;
  978.     struct srec *drec;
  979.  
  980.     count += ovrhd;
  981.     for (i = 0, drec = rec[space]; i < (optm ? wsize : 1); i++, drec++) {
  982.         drec->checksum += (unsigned)sum_addr (addr);
  983.         if (mach == DSP56000 || mach == DSP5616)
  984.             (void)sprintf (strbuf, "S1%02lx%04lx%s%02x\n",
  985.                  count, addr, drec->buf,
  986.                  ~(drec->checksum + count) & 0xff);
  987.         else
  988.             (void)sprintf (strbuf, "S3%02lx%08lx%s%02x\n",
  989.                  count, addr, drec->buf,
  990.                  ~(drec->checksum + count) & 0xff);
  991.         fputs (strup (strbuf), drec->fp);
  992.         drec->checksum = 0;
  993.         drec->p = drec->buf;
  994.     }
  995. }
  996.  
  997.  
  998. static
  999. rev_bytes ()        /* reverse the bytes in fldbuf */
  1000. {
  1001.     char c;
  1002.  
  1003.     switch (mach) {
  1004.     case DSP96000:
  1005.         c = fldbuf[0];
  1006.         fldbuf[0] = fldbuf[6];
  1007.         fldbuf[6] = c;
  1008.         c = fldbuf[1];
  1009.         fldbuf[1] = fldbuf[7];
  1010.         fldbuf[7] = c;
  1011.         c = fldbuf[2];
  1012.         fldbuf[2] = fldbuf[4];
  1013.         fldbuf[4] = c;
  1014.         c = fldbuf[3];
  1015.         fldbuf[3] = fldbuf[5];
  1016.         fldbuf[5] = c;
  1017.         break;
  1018.     case DSP5616:
  1019.         c = fldbuf[0];
  1020.         fldbuf[0] = fldbuf[2];
  1021.         fldbuf[2] = c;
  1022.         c = fldbuf[1];
  1023.         fldbuf[1] = fldbuf[3];
  1024.         fldbuf[3] = c;
  1025.         break;
  1026.     case DSP56000:
  1027.     default:
  1028.         c = fldbuf[0];
  1029.         fldbuf[0] = fldbuf[4];
  1030.         fldbuf[4] = c;
  1031.         c = fldbuf[1];
  1032.         fldbuf[1] = fldbuf[5];
  1033.         fldbuf[5] = c;
  1034.         break;
  1035.     }
  1036. }
  1037.  
  1038.  
  1039. static
  1040. open_files (space)    /* open S-record ouput files */
  1041. int space;
  1042. {
  1043.     struct srec *drec;
  1044.     char fn[MAXSTR], *p;
  1045.     register i;
  1046.     char c;
  1047.  
  1048. /*
  1049.     allocate S-record structure array; construct output file name
  1050. */
  1051.  
  1052.     if ((drec = (struct srec *)calloc (optm ? (unsigned)wsize :
  1053.                        (unsigned)1,
  1054.                        sizeof (struct srec))) == NULL)
  1055.         error ("cannot allocate S-record structure");
  1056.     rec[space] = drec;        /* squirrel pointer away */
  1057.     if (ifname) {    /* if explicit input file */
  1058.         c = opts ? 's' : fldbuf[0];
  1059.         (void)sprintf (fn, "%s.%c",
  1060.                    ifname, isupper (c) ? tolower (c) : c);
  1061.         p = fn + strlen (fn);
  1062.     }
  1063.  
  1064. /*
  1065.     loop to open all files, write out S0 record
  1066. */
  1067.  
  1068.     if (!optm) {        /* don't need multiple files */
  1069.         if (!ifname)
  1070.             drec->fp = stdout;    /* if all else fails... */
  1071.         else {
  1072.             if ((drec->fp = fopen (fn, "w")) == NULL)
  1073.                 error2 ("cannot open output file %s", fn);
  1074.             (void) setfile (fn, "TEXT", "MPS ");
  1075.         }
  1076.         if (!opts)
  1077.             fputs (s0buf, drec->fp);
  1078.     } else
  1079.         for (i = wsize - 1, rec[space] = drec; i >= 0; i--, drec++) {
  1080.             if (!ifname)
  1081.                 drec->fp = stdout;
  1082.             else {
  1083.                 *p = (char)(i + '0');
  1084.                 *(p + 1) = EOS;
  1085.                 if ((drec->fp = fopen (fn, "w")) == NULL)
  1086.                     error2 ("cannot open output file %s",
  1087.                         fn);
  1088.                 (void) setfile (fn, "TEXT", "MPS ");
  1089.             }
  1090.             fputs (s0buf, drec->fp);
  1091.         }
  1092. }
  1093.  
  1094.  
  1095. static
  1096. get_field ()        /* get next field from ifile; put in fldbuf */
  1097. {
  1098.     register c;
  1099.     register char *p;
  1100.  
  1101.     while ((c = fgetc (ifile)) != EOF && isspace (c))
  1102.         if (c == '\n')
  1103.             linecount++;
  1104.  
  1105.     if (c == EOF)            /* end of object file */
  1106.         return (EOF);
  1107.  
  1108.     for (p = fldbuf, *p++ = c;    /* loop to pick up field value */
  1109.          (c = fgetc (ifile)) != EOF && !isspace (c);
  1110.          *p++ = c)
  1111.         ;
  1112.  
  1113.     *p = EOS;            /* null at end of value */
  1114.     if (c != EOF)
  1115.         (void)ungetc (c, ifile); /* put back last char. if not EOF */
  1116.  
  1117.     return (*fldbuf == NEWREC ? 1 : 0);/* let caller know if new record */
  1118. }
  1119.  
  1120.  
  1121. static
  1122. get_comment ()        /* get comment from load file; put in fldbuf */
  1123. {
  1124.     register c;
  1125.     register char *p;
  1126.  
  1127.     while ((c = fgetc (ifile)) != EOF && c != '\n' && isspace (c))
  1128.         ;            /* skip white space (except newline) */
  1129.  
  1130.     if (c == EOF || c != '\n')    /* end of file or synch error */
  1131.         return (EOF);
  1132.  
  1133.     linecount++;
  1134.     for (p = fldbuf; (c = fgetc (ifile)) != EOF && c != '\n'; *p++ = c)
  1135.         ;            /* loop to pick up comment */
  1136.     if (c == '\n')
  1137.         linecount++;
  1138.  
  1139.     *p = EOS;            /* null at end of comment */
  1140.  
  1141.     return (0);            /* good return */
  1142. }
  1143.  
  1144.  
  1145. static
  1146. get_line ()        /* buffer line in strbuf */
  1147. {
  1148.     register char *p;
  1149.     register c;
  1150.  
  1151.     for (p = strbuf; (c = fgetc (ifile)) != EOF && c != '\n'; p++)
  1152.         *p = c;
  1153.     if (c == EOF || c != '\n')    /* end of file or synch error */
  1154.         return (EOF);
  1155.     *p = EOS;
  1156.     (void)ungetc (c, ifile);    /* put back new line */
  1157.     return (0);
  1158. }
  1159.  
  1160.  
  1161. static char *
  1162. scan_field (bp)        /* scan next field in strbuf; put in fldbuf */
  1163. register char *bp;
  1164. {
  1165.     register char *p;
  1166.  
  1167.     while (*bp && isspace (*bp))
  1168.         bp++;
  1169.  
  1170.     if (!*bp)            /* end of line */
  1171.         return (NULL);
  1172.  
  1173.     for (p = fldbuf; *bp && !isspace (*bp); *p++ = *bp++)
  1174.         ;            /* loop to pick up field value */
  1175.     *p = EOS;            /* null at end of value */
  1176.  
  1177.     return (bp);            /* return current line pointer */
  1178. }
  1179.  
  1180.  
  1181. static
  1182. bld_s0 (space)
  1183. unsigned space;
  1184. {
  1185.     static char s0name[MAXSTR];
  1186.  
  1187.     if (space == NONE)
  1188.         (void)strcpy (s0name, s0buf);
  1189.     (void)sprintf (s0buf, "S0%02x%04x%s%02x\n",
  1190.         s0cnt, space, s0name, ~(s0sum + s0cnt + space) & 0xff);
  1191.     (void)strup (s0buf);
  1192. }
  1193.  
  1194.  
  1195. static
  1196. setup_mach (buf)
  1197. char *buf;
  1198. {
  1199.     int mach = NONE;
  1200.  
  1201.     if (strcmp (buf, "56000") == 0) {
  1202.         mach = DSP56000;
  1203.         wsize = WSIZE5;
  1204.         ovrhd = OVRHD5;
  1205.         wrdfmt = WRDFMT5;
  1206.     } else if (strcmp (buf, "96000") == 0) {
  1207.         mach = DSP96000;
  1208.         wsize = WSIZE9;
  1209.         ovrhd = OVRHD9;
  1210.         wrdfmt = WRDFMT9;
  1211.     } else if (strcmp (buf, "5616") == 0) {
  1212.         mach = DSP5616;
  1213.         wsize = WSIZE6;
  1214.         ovrhd = OVRHD6;
  1215.         wrdfmt = WRDFMT6;
  1216.     }
  1217.     return (mach);
  1218. }
  1219.  
  1220.  
  1221. static
  1222. get_space ()            /* return memory space attribute */
  1223. {
  1224.     switch (fldbuf[0]) {
  1225.     case 'X':
  1226.     case 'x':
  1227.         return (XMEM);
  1228.     case 'Y':
  1229.     case 'y':
  1230.         return (YMEM);
  1231.     case 'P':
  1232.     case 'p':
  1233.         return (PMEM);
  1234.     case 'L':
  1235.     case 'l':
  1236.         return (LMEM);
  1237.     default:
  1238.         return (-1);
  1239.     }
  1240. }
  1241.  
  1242.  
  1243. static char *
  1244. fix_fname (fname)        /* add extension to file name if reqd */
  1245. char *fname;
  1246. {
  1247.     int len = strlen (fname);
  1248.     char *fn;
  1249.     register char *p, *np, *ep = NULL;
  1250.     static char *defext = ".lod";
  1251.  
  1252.     if ((fn = malloc ((unsigned)(len + MAXEXTLEN + 1))) == NULL)
  1253.         error ("cannot allocate file name");
  1254.     (void)strcpy (fn, fname);
  1255.  
  1256.     np = p = fn + len;     /* save end */
  1257.  
  1258.     while (p != fn) {
  1259.         if (*--p == '.')
  1260.             ep = p;
  1261. #if MSDOS
  1262.         if (*p == '\\' || *p == ':')
  1263. #endif
  1264. #if VMS
  1265.         if (*p == ']' || *p == ':')
  1266. #endif
  1267. #if UNIX
  1268.         if (*p == '/')
  1269. #endif
  1270. #if MAC
  1271.         if (*p == ':')
  1272. #endif
  1273.             break;
  1274.         else
  1275.             continue;
  1276.         }
  1277.     if (p != fn)
  1278.         p++;
  1279.  
  1280.     if (!ep) {    /* no extension supplied */
  1281.         (void)strcpy (np, defext);
  1282.         ep = np;
  1283.         np += strlen (defext);
  1284.     }
  1285.  
  1286.     if (np - p > BASENAMLEN) {    /* filename too long -- truncate */
  1287.         np = p + (BASENAMLEN - MAXEXTLEN);
  1288.         p = np;
  1289.         while (*ep && np < p + MAXEXTLEN)
  1290.             *np++ = *ep++;
  1291.         *np = EOS;
  1292.     }
  1293.     return (fn);
  1294. }
  1295.  
  1296.  
  1297. static char *
  1298. strup (str)            /* convert all alpha chars in str to upper */
  1299. char *str;
  1300. {
  1301.     register char *p = str;
  1302.  
  1303.     while (*p) {
  1304.         if (isalpha (*p) && islower (*p))
  1305.             *p = toupper (*p);
  1306.         p++;
  1307.     }
  1308.     return (str);
  1309. }
  1310.  
  1311.  
  1312. static
  1313. fldhex ()            /* insure fldbuf contains hex value */
  1314. {
  1315.     register char *p = fldbuf;
  1316.  
  1317.     while (*p) {
  1318.         if (!isxdigit (*p))
  1319.             break;
  1320.         p++;
  1321.     }
  1322.     if (!*p)
  1323.         return (YES);
  1324.     else
  1325.         return (NO);
  1326. }
  1327.  
  1328.  
  1329. static char *
  1330. basename (str)            /* return base part of file name in str */
  1331. char *str;
  1332. {
  1333.     register char *p;
  1334.  
  1335.     if (!str)        /* empty input */
  1336.         return (NULL);
  1337.  
  1338.     for (p = str + strlen (str); p >= str; --p)
  1339. #if MSDOS
  1340.         if( *p == '\\' || *p == ':')
  1341. #endif
  1342. #if VMS
  1343.         if( *p == ']' || *p == ':')
  1344. #endif
  1345. #if UNIX
  1346.         if( *p == '/' )
  1347. #endif
  1348. #if MAC
  1349.         if( *p == ':' )
  1350. #endif
  1351.             break;
  1352.  
  1353.     return (p < str ? str : ++p);
  1354. }
  1355.  
  1356.  
  1357. /**
  1358. * name        setfile --- set the file type and creator if necessary
  1359. *
  1360. * synopsis    yn = setfile (fn, type, creator)
  1361. *        int yn;        YES on success, NO on failure
  1362. *        char *fn;    pointer to file name
  1363. *        char *type;    pointer to file type
  1364. *        char *creator;    pointer to file creator
  1365. *
  1366. * description    Sets the file type and creator for newly-created Macintosh
  1367. *        output files.  Simply returns YES on other hosts.
  1368. *
  1369. **/
  1370. static
  1371. setfile (fn, type, creator)
  1372. char *fn, *type, *creator;
  1373. {
  1374. #if MPW
  1375.     int i;
  1376.     short status;
  1377.     struct FInfo finfo;
  1378.     OSType val;
  1379.     Str255 buf;
  1380.  
  1381.     (void) strcpy (&buf[1], fn);
  1382.     buf[0] = strlen (fn);
  1383.     if ((status = GetFInfo (buf, (short)0, &finfo)) != 0)
  1384.         return (NO);
  1385.     i = 0;
  1386.     val = (OSType) 0;
  1387.     while (i < sizeof (OSType)) {
  1388.         val <<= (OSType) 8;
  1389.         val += (OSType) type[i++];
  1390.     }
  1391.     finfo.fdType = val;
  1392.     i = 0;
  1393.     val = (OSType) 0;
  1394.     while (i < sizeof (OSType)) {
  1395.         val <<= (OSType) 8;
  1396.         val += (OSType) creator[i++];
  1397.     }
  1398.     finfo.fdCreator = val;
  1399.     if ((status = SetFInfo (buf, (short)0, &finfo)) != 0)
  1400.         return (NO);
  1401. #endif
  1402. #if LINT
  1403.     fn = fn;
  1404.     type = type;
  1405.     creator = creator;
  1406. #endif
  1407.     return (YES);
  1408. }
  1409.  
  1410.  
  1411. getopt (argc, argv, optstring)    /* get option letter from argv */
  1412. int argc;
  1413. char *argv[];
  1414. char *optstring;
  1415. {
  1416.     register char c;
  1417.     register char *place;
  1418.     static char *scan = NULL;
  1419.     extern char *index();
  1420.  
  1421.     optarg = NULL;
  1422.  
  1423.     if (scan == NULL || *scan == '\0') {
  1424.         if (optind == 0)
  1425.             optind++;
  1426.     
  1427.         if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  1428.             return(EOF);
  1429.         if (strcmp(argv[optind], "--")==0) {
  1430.             optind++;
  1431.             return(EOF);
  1432.         }
  1433.     
  1434.         scan = argv[optind]+1;
  1435.         optind++;
  1436.     }
  1437.  
  1438.     c = *scan++;
  1439.     place = index(optstring, c);
  1440.  
  1441.     if (place == NULL || c == ':') {
  1442.         (void)fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
  1443.         return('?');
  1444.     }
  1445.  
  1446.     place++;
  1447.     if (*place == ':') {
  1448.         if (*scan != '\0') {
  1449.             optarg = scan;
  1450.             scan = NULL;
  1451.         } else if (optind < argc) {
  1452.             optarg = argv[optind];
  1453.             optind++;
  1454.         } else {
  1455.             (void)fprintf( stderr, "%s: -%c argument missing\n", 
  1456.                     argv[0], c);
  1457.             return( '?' );
  1458.         }
  1459.     }
  1460.  
  1461.     return(c);
  1462. }
  1463.  
  1464.  
  1465. /**
  1466. *
  1467. * name        dcl_getval - get DCL command line value
  1468. *
  1469. * synopsis    status = dcl_getval (opt)
  1470. *        int status;    return status from cli$get_value
  1471. *        struct dsc$descriptor_s *opt;    pointer to command line option
  1472. *
  1473. * description    Calls the VMS DCL routine cli$get_value to return values
  1474. *        for the command line option referenced by opt.  The values
  1475. *        are returned in the global dclbuf array.  The length returned
  1476. *        from cli$get_value is used to terminate the string.
  1477. *
  1478. **/
  1479. static
  1480. dcl_getval (opt)
  1481. #if VMS
  1482. struct dsc$descriptor_s *opt;
  1483. #else
  1484. int *opt;
  1485. #endif
  1486. {
  1487. #if VMS
  1488.     unsigned status, len = 0;
  1489.     
  1490.     status = cli$get_value (opt, &arg_desc, &len);
  1491.     if (status != CLI$_ABSENT)
  1492.         dclbuf[len] = EOS;
  1493.     return (status);
  1494. #else
  1495.     return (*opt);
  1496. #endif
  1497. }
  1498.  
  1499.  
  1500. #if VMS
  1501. /**
  1502. *
  1503. * name        dcl_reset - reset DCL command line
  1504. *
  1505. * synopsis    yn = dcl_reset ()
  1506. *        int yn;        YES/NO for errors
  1507. *
  1508. * description    Resets the DCL command line so that it may be reparsed.
  1509. *        Returns YES if command line is reset, NO on error.
  1510. *
  1511. **/
  1512. static
  1513. dcl_reset ()
  1514. {
  1515.     return (cli$dcl_parse(NULL, NULL) == CLI$_NORMAL);
  1516. }
  1517. #endif
  1518.  
  1519.  
  1520. #if BSD
  1521. static
  1522. #else
  1523. static void
  1524. #endif
  1525. onintr ()            /* clean up from signal */
  1526. {
  1527.     error ("Interrupted");
  1528. }
  1529.  
  1530.  
  1531. static
  1532. usage ()            /* display usage on stderr, exit nonzero */
  1533. {
  1534. #if !MSDOS
  1535.         (void)fprintf (stderr, "%s  %s\n%s\n", Progtitle, Version, Copyright);
  1536. #endif
  1537.     (void)fprintf (stderr, "Usage: %s [-blmrsw] [-p <procno>] <input file ... >\n",    Progname);
  1538.     (void) fprintf (stderr, "        b - byte addressing\n");
  1539.     (void) fprintf (stderr, "        l - long (double-word) addressing\n");
  1540.     (void) fprintf (stderr, "        m - multiple output files\n");
  1541.     (void) fprintf (stderr, "        p - <procno> load file format\n");
  1542.     (void) fprintf (stderr, "        r - reverse bytes in word\n");
  1543.     (void) fprintf (stderr, "        s - single output file\n");
  1544.     (void) fprintf (stderr, "        w - word addressing\n");
  1545. #if LSC
  1546.     longjmp (Env, 1);
  1547. #else
  1548.     exit (ERR);
  1549. #endif
  1550. }
  1551.  
  1552.  
  1553. static
  1554. error (str)
  1555. char *str;
  1556. {
  1557.     (void)fprintf (stderr, "%s: at line %d: ", Progname, linecount);
  1558.     (void)fprintf (stderr, "%s\n", str);
  1559. #if LSC
  1560.     longjmp (Env, 1);
  1561. #else
  1562.     exit (ERR);
  1563. #endif
  1564. }
  1565.  
  1566.  
  1567. static
  1568. error2 (fmt, str)
  1569. char *fmt, *str;
  1570. {
  1571.     (void)fprintf (stderr, "%s: at line %d: ", Progname, linecount);
  1572.     (void)fprintf (stderr, fmt, str);
  1573.     (void)fprintf (stderr, "\n");
  1574. #if LSC
  1575.     longjmp (Env, 1);
  1576. #else
  1577.     exit (ERR);
  1578. #endif
  1579. }
  1580.